package com.astronomia.wheels.lambda;

import com.alibaba.fastjson.JSON;
import com.astronomia.wheels.pojo.Person;
import com.astronomia.wheels.pojo.TreePojo;

import java.text.Collator;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.astronomia.wheels.pojo.TreePojo.getList;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.averagingInt;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
 * LambdaUtils
 **/
public class LambdaUtils {

    /**
     * lambda 表达式的语法格式如下：
     * (parameters) -> expression
     * 或
     * (parameters) ->{ statements; }
     *
     * 以下是lambda表达式的重要特征:
     *   可选类型声明：不需要声明参数类型，编译器可以统一识别参数值。
     *   可选的参数圆括号：一个参数无需定义圆括号，但多个参数需要定义圆括号。
     *   可选的大括号：如果主体包含了一个语句，就不需要使用大括号。
     *   可选的返回关键字：如果主体只有一个表达式返回值则编译器会自动返回值，大括号需要指定明表达式返回了一个数值。
     */
    public static void main(String[] args) {

        List<Person> personList = Person.getList();

        personList.forEach(person -> System.out.println(person.getAge() + "=" + person.getName()));

        //--------------------------------------------------------中间操作---------------------------------------------------
        Predicate<Person> ageFilter = (person -> person.getAge() > 3);
        System.out.println("过滤------");
        List<Person> personList1 = personList.stream().filter(ageFilter).collect(Collectors.toList());
        System.out.println(personList1);

        System.out.println("逆序排序------");
        List<Person> collect = personList.stream().sorted(comparing(Person::getAge).reversed()).collect(Collectors.toList());
        collect.forEach(System.out::println);

        System.out.println("逆序排序2------");
        List<Integer> integerList = Arrays.asList(1, 2, 9, 6, 5, 6, 8);
        List<Integer> collect0 = integerList.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList());
        System.out.println(collect0);

        System.out.println("截取------");
        List<Person> collect1 = personList.stream().sorted(comparing(Person::getAge)).limit(3).collect(Collectors.toList());
        collect1.forEach(System.out::println);

        System.out.println("跳过------");
        List<Person> collect2 = personList.stream().sorted(comparing(Person::getAge)).skip(1).collect(Collectors.toList());
        collect2.forEach(System.out::println);

        System.out.println("拼串，‘;’隔开------");
        String str = personList.stream().sorted(comparing(Person::getAge)).map(Person::getName)
                .collect(Collectors.joining(";"));
        System.out.println(str);

        System.out.println("数据统计------");
        IntSummaryStatistics statistics = personList.stream().mapToInt(Person::getAge).summaryStatistics();
        System.out.println("max===" + statistics.getMax() + "  min===" + statistics.getMin() + "  average==="
                + statistics.getAverage() + "  count===" + statistics.getCount() + "  sum===" + statistics.getSum());

        System.out.println("去重，完全相同的对象------");
        List<Person> distinct = personList.stream().distinct().collect(Collectors.toList());
        System.out.println(distinct);

        String[] strs = {"java8", "is", "easy", "to", "use"};
        System.out.println("映射成为Stream<String[]>，去重无用------");
        List<String[]> distinctStrs = Arrays.stream(strs).map(str1 -> str1.split("")).distinct().collect(Collectors.toList());
        System.out.println(JSON.toJSONString(distinctStrs));

        System.out.println("将多个流扁平化一个流，并去重------");
        List<String> flatMap = Arrays.stream(strs).map(str1 -> str1.split("")).flatMap(Arrays::stream)
                .distinct().collect(Collectors.toList());
        System.out.println(flatMap);

        //--------------------------------------------------终端操作-------------------------------------------------------------
        System.out.println("流中所有数据是否都满足条件------");
        boolean b = personList.stream().allMatch(person -> person.getAge() > 0);
        System.out.println(b);

        System.out.println("流中所有数据是否有与条件匹配的------");
        boolean a = personList.stream().anyMatch(person -> person.getAge() > 1);
        System.out.println(a);

        System.out.println("流中所有数据是否没有与条件匹配的------");
        boolean n = personList.stream().noneMatch(person -> person.getAge() > 8);
        System.out.println(n);

        System.out.println("获取流中第一条数据------");
        Optional<Person> first = personList.stream().findFirst();
        System.out.println(first);

        System.out.println("获取流中任意一条数据------");
        Optional<Person> any = personList.stream().findAny();
        System.out.println(any);

        System.out.println("求和------");
        Long sum1 = personList.stream().count();
        System.out.println(sum1);

        System.out.println("最小------");
        Person person1 = personList.stream().min(comparing(Person::getAge)).get();
        System.out.println(JSON.toJSONString(person1));

        System.out.println("最大------");
        Person person2 = personList.stream().max(comparing(Person::getAge)).get();
        System.out.println(JSON.toJSONString(person2));

        System.out.println("求和------");
        int sum = personList.stream().mapToInt(Person::getAge).sum();
        System.out.println(sum);

        System.out.println("获取年龄总和------");
        Integer reduce = personList.stream().map(Person::getAge).reduce(0, Integer::sum);
        System.out.println(reduce);

        System.out.println("字符串拼接------");
        String names = personList.stream()
                .map(Person::getName).collect(Collectors.joining(",", "[", "]"));
        System.out.println(names);

        System.out.println("平均年龄------");
        Double avgAge = personList.stream().collect(averagingInt(Person::getAge));
        System.out.println(avgAge);


        //-------------------------------------------------收集---------------------------------------------------------
        System.out.println("存到set里------");
        Set<String> nameSet = personList.stream().map(Person::getName).collect(toSet());
        System.out.println(nameSet);

        System.out.println("存到treeSet里------");
        Set<String> nameTreeSet = personList.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
        System.out.println(nameTreeSet);

        System.out.println("存到map里------");
        Map<String, List<Person>> collect3 = personList.stream().collect(Collectors.groupingBy(Person::getName));
        System.out.println(collect3);

        System.out.println("存到map里，遇到重复Key，新值换旧值------");
        Map<Integer, String> map = personList.stream().collect(Collectors.toMap(Person::getAge, Person::getName,
                (oldValue, newValue) -> newValue));
        System.out.println(map);

        System.out.println("多重分组------");
        Map<Integer, Map<String, List<Person>>> collect4 = personList.stream().collect(
                Collectors.groupingBy(Person::getAge,  // 一级分组，按年龄
                        Collectors.groupingBy(Person::getName)));// 二级分组，按名字
        System.out.println(collect4);

        System.out.println("分区------");
        Map<Boolean, List<Person>> partition = personList.stream().collect(
                Collectors.partitioningBy(student -> student.getAge() == 6));
        System.out.println(partition);

        System.out.println("获取年龄最大的------");
        Person person = personList.stream().max(comparing(Person::getAge)).orElseGet(Person::new);
        System.out.println(person);

        System.out.println("根据指定字段排序(注意：不能排字母)------");
        List<Person> collect5 = personList.stream().sorted(comparing(r -> {
            Collator collator = Collator.getInstance(Locale.CHINA);
            return collator.getCollationKey(r.getName());
        })).collect(Collectors.toList());
        System.out.println(collect5);

        System.out.println("分组，取每组最大------");
        List<Person> list2 = Person.getList2();
        Map<String, Person> collect6 = list2.stream().collect(Collectors.toMap(Person::getName, Function.identity(), (c1, c2) -> c1.getAge() > c2.getAge() ? c1 : c2));
        System.out.println(collect6);

        System.out.println("分组，对另一个值进行拼接1------");
        List<Person> list3 = Person.getList2();
        Map<Integer, String> collect7 = list3.stream().collect(Collectors.toMap(Person::getAge, Person::getName, (s, s2) -> s + ", " + s2));
        System.out.println(JSON.toJSON(collect7));

        System.out.println("分组，对另一个值进行拼接2------");
        List<Person> list4 = Person.getList2();
        Map<Integer, String> collect8 = list4.stream().collect(Collectors.groupingBy(Person::getAge, Collectors.mapping(Person::getName, joining("、"))));
        System.out.println(JSON.toJSON(collect8));

        System.out.println("分组，包含空值------");
        List<Person> list5 = Person.getList4();
        Map<String, List<Person>> collect10 = list5.stream().collect(Collectors.groupingBy(x -> Optional.ofNullable(x.getName()).orElse("指定key值")));
        System.out.println(JSON.toJSON(collect10));

        System.out.println("双重排序------");
        List<Person> collect9 = Person.getList3().stream().sorted(comparing(Person::getAge).thenComparing(Person::getDate, Comparator.reverseOrder())).collect(toList());
        System.out.println(JSON.toJSON(collect9));

        System.out.println("分组后统计条数-----------");
        Map<Integer, Long> countMap = Person.getList().stream().collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
        for (Map.Entry<Integer, Long> entry : countMap.entrySet()) {
            System.out.println(entry.getValue());
            if (entry.getValue() > 1) {
                return;
            }
        }
        System.out.println(JSON.toJSON(countMap));

        System.out.println("组装三级树------------");
        List<TreePojo> list = getList();
        List<TreePojo> collect12 = list.stream()
                .filter(l1 -> l1.getPId() == null && l1.getId() == null)
                .peek(p1 -> p1.setTreePojoList(
                        list.stream()
                                .filter(l2 -> p1.getId().equals(l2.getPId()))
                                .peek(p2 -> p2.setTreePojoList(
                                        list.stream()
                                                .filter(l3 -> p2.getId().equals(l3.getPId()))
                                                .collect(Collectors.toList())))
                                .collect(Collectors.toList())))
                .collect(Collectors.toList());
        System.out.println(JSON.toJSONString(collect12));

    }

}
